import com.google.gdata.data.extensions.Where;
import java.io.File;
import java.io.FileNotFoundException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Scanner;


/**Performs all tasks related to the timetable file and data
 * @author Sean Reece
 */
public class Timetable {
	//Constants
	private static final int FNOR = 1;	//Normal file status (everything is fine)
	private static final int FDEF = 0;	//File Default State
	private static final int FERR = -1;	//File Error
	private static final int FDNE = -2; //File Does not exist
	
	//Fields
	private Scanner fileInput;
	
	private static HashMap<String,String> courseNames = new HashMap<String,String>();
	private static int fileStatus = FDEF;
	private static String studentID;
	private static String day = null;
	private static String course;
	private static String delivery;
	private static String building;
	private static String room;
	private static String professor;
	private static Date startDate = null;
	private static Date endDate = null;
	private static Date untilDate = null;
	private static Where location;
	

	/**Constructor for timetable.
	 * Tries to open the timetable html file and creates the scanner.
	 * If html file does not exist or is not proper, <code>fileStatus</code> error flag set and return.
	 * 
	 * @param file The html file that contains event data
	 */
	 public Timetable(File file) {
		 if (file == null){
			 fileStatus = FDNE; 
			 return;
		 }
		 try {
			 fileInput = new Scanner(file);
			 fileStatus = FNOR;
		 } catch (FileNotFoundException ex) {
			 fileStatus = FDNE;    //File doesn't exist
			 return;
		 }
		 
		 fileInput.useDelimiter("[<][tT][dD]");
		 if (!findStudentID()){
			 fileStatus = FERR;    //File isn't a proper timetable
			 return;
		 }
		 findCourseNames();
	 }

	 /**Implements very basic HTML parser to search for student id
	  * Uses non-greedy regular expression to remove tags
	  * 
	  * @return The student ID as a string
	  */
	 public boolean findStudentID(){
		 String id;
		 while (fileInput.hasNext()) {
			 id = fileInput.next();
			 id = id.replaceAll("<.+?>", "");
			 if (id.contains("Student Id:")){
				 studentID = id;
				 return true;
			 }
		 }
		 fileInput.close();
		 return false;
	 }

	 /**Runs through html file looking for the names and course number of student's 
	  * current courses. Puts data into a hashmap with the course number as the key.
	  * If no courses were found then method sets <code>fileStatus</code> flag to -1 and returns.
	  */
	 public void findCourseNames(){
		 String item, course, courseName;
		 while (fileInput.hasNext()) {
			 item = fileInput.next().replaceAll("<.+?>", "");
			 if (item.contains("End Date")){
				 while (!(course = fileInput.nextLine().replaceAll("<.+?>|[*]", "")).contains("Daily Timetable")){
					 courseName = fileInput.nextLine().replaceAll("<.+?>", "");
					 courseNames.put(course, courseName);
					 //Skip to next course
					 for (int i=0;i<=4;i++){
						 item = fileInput.nextLine();
					 }
				 }
				 return;
			 }
		 }
		 fileInput.close();
		 fileStatus = FERR;	//No courses found
	 }
	 /**Runs through html file until a class event is found, then <code>parseCourse()</code> is called.
	  * 
	  * @return True if a class was found. False if end of file reached (no more classes)
	  */
	 public boolean findNextClass(){
		 String check;
		 while (fileInput.hasNext()){
			 check = fileInput.next();
			 check = check.replaceAll("<.+?>", "");
			 if (check.contains("TBA")){
				 continue;
			 }
			 else if (check.contains("Mon")||check.contains("Tue")||check.contains("Wed")||check.contains("Thu")||check.contains("Fri")||check.contains("Sat")||check.contains("Sun")){
				 day = check.replaceAll(".*>", "").replaceAll("\\s", "");
				 parseCourse();
				 return true;
			 }
		 }
		 fileInput.close();
		 return false;	//No Classes Left
	 }

	 /**Must be called by <code>findNextClass()</code>! 
	  * Once a class event is found, method will go through html file line by line saving the relative information about the event.
	  * The method will not check if information is valid but determines information based in location.
	  * 
	  */
	 private void parseCourse(){
		 String item, startTime = null, endTime = null, startDateStr, endDateStr, untilDateStr;

		 SimpleDateFormat formatDateTime =
			 new SimpleDateFormat("dd-MMM-yyyykk:mm");

		 /*Class Start Time*/
		 item = fileInput.nextLine().replaceAll("<.+?>", "");
		 if (!item.equals("TBA")){
			 startTime = item;
		 }

		 /*Class End Time*/
		 item = fileInput.nextLine().replaceAll("<.+?>", "");	
		 if (!item.equals("TBA")){
			 endTime = item;
		 }

		 /*Campus*/
		 fileInput.nextLine();

		 /*Building*/
		 building = fileInput.nextLine().replaceAll("<.+?>", "");

		 /*Room*/
		 room = fileInput.next().replaceAll("<.+?>", "").replaceAll(".*?>", "");

		 /*Course Start Date*/
		 item = fileInput.next().replaceAll("<.+?>", "");
		 item = item.replaceAll(".+?>", "");
		 item = item.replaceAll("\\s", "");

		 startDateStr = item.concat(startTime);
		 endDateStr = item.concat(endTime);

		 try {
			 startDate = formatDateTime.parse(startDateStr);
			 endDate = formatDateTime.parse(endDateStr);
		 } catch (ParseException e) {
			 e.printStackTrace();
		 }

		 /*Course End Date*/
		 item = fileInput.next().replaceAll("<.+?>", "");
		 item = item.replaceAll(".+?>", "");
		 item = item.replaceAll("\\s", "");
		 untilDateStr = item.concat(endTime);

		 try {
			 untilDate = formatDateTime.parse(untilDateStr);
		 } catch (ParseException e) {
			 e.printStackTrace();
		 }

		 /*Academic Penalty Withdrawal Date*/
		 fileInput.nextLine();

		 /*Blank*/
		 fileInput.nextLine();
		 fileInput.next();

		 /*Course*/
		 course = new String(fileInput.nextLine().replaceAll("<.+?>", "").substring(8));

		 /*Section*/
		 item = fileInput.nextLine();

		 /*Delivery*/
		 delivery = new String(fileInput.nextLine().replaceAll("<.+?>", "").substring(11));

		 /*Blank*/
		 fileInput.nextLine();
		 fileInput.nextLine();

		 /*Professor*/
		 professor = fileInput.nextLine().replaceAll("<.+?>", "");
	 }
	 
	 //Get methods
	 
	 public static int getFileStatus(){
		 return fileStatus;
	 }
	 public static String getStudentID(){
		 return studentID;
	 }
	 public static String getDay(){
		 return day;
	 }
	 /**
	  * Used for recurrence data where short day format must be used (eg. Mon, Tue, Wed)
	  * @return A substring of the day an event occurs on.
	  */
	 public static String getDayShort(){
		 return day.substring(0,2);
	 }
	 /**
	  * @return Date and time the class begins on.
	  */
	 public static Date getStartDate(){
		 return startDate;
	 }
	 /** The date will be the same as <code>getStartDate()</code>. Used for the end time of a class.
	  * @return The time that the class ends on.
	  */
	 public static Date getEndDate(){
		 return endDate;
	 }
	 /**
	  * The last day of class. No Valuable time information is kept in this field. 
	  * @return The last day the class will be held. Event recurs until this date. 
	  */
	 public static Date getUntilDate(){
		 return untilDate;
	 }
	 /**
	  * 
	  * @return The course code
	  */
	 public static String getCourse(){
		 return course;
	 }
	 /**
	  * 
	  * @return The full name of the course
	  */
	 public static String getCourseName(){
		 return courseNames.get(getCourse());
	 }
	 /**
	  * 
	  * @return Type of class (eg. theory, lab)
	  */
	 public static String getDelivery(){
		 return delivery;
	 }
	 /**
	  * 
	  * @return The location of the classroom
	  */
	 public static Where getLocation(){
		 location = new Where();
		 location.setValueString(building+"-"+room);
		 return location;
	 }
	 /**
	  * 
	  * @return Professor's name
	  */
	 public static String getProfessor(){
		 return professor;
	 }

}
